package com.wcbtest.oshi.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.system.HostInfo;
import cn.hutool.system.SystemUtil;
import cn.hutool.system.oshi.OshiUtil;
import com.wcbtest.oshi.domain.*;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import oshi.SystemInfo;
import oshi.hardware.*;
import oshi.hardware.CentralProcessor.TickType;
import oshi.software.os.*;
import oshi.util.FormatUtil;
import oshi.util.Util;

import java.io.Serializable;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@ApiModel(value = "获取系统硬件信息（所有信息）")
@Data
public class OshiUtils implements Serializable {

    private static final long serialVersionUID = 1L;

    private static final int OSHI_WAIT_SECOND = 1000;

    /**
     * CPU相关信息
     */
    private Cpu cpu = new Cpu();

    /**
     * 內存相关信息
     */
    private Mem mem = new Mem();

    /**
     * JVM相关信息
     */
    private Jvm jvm = new Jvm();

    /**
     * 服务器相关信息
     */
    private OSSys Sys = new OSSys();
    /**
     * 硬件硬盘
     */
    private List<DiskStores> diskStores = new ArrayList<>();

    /**
     * 磁盘相关信息
     */
    private List<FileSys> fileSys = new LinkedList<FileSys>();

    /**
     * 进程相关信息
     */
    public List<Proc> procs = new ArrayList<>();


    public static void main(String[] args) {
        SystemInfo systemInfo = new SystemInfo();
        OperatingSystem os = systemInfo.getOperatingSystem();
        List<OSProcess> java = os.getProcesses(
                osProcess -> StrUtil.equalsIgnoreCase(osProcess.getName(), "java"),
                OperatingSystem.ProcessSorting.CPU_DESC,
                20);
        System.out.println(java);
    }

    /**
     * 调用此方法初始化数据
     *
     * @throws Exception
     */
    public void initData() {

        this.cpu = getCpuInfo();

        this.jvm = getJvmInfo();

        this.mem = getMemInfo();


        this.Sys = getSysInfo();

        //this.fileSys = getOsDiskFile();

        //this.diskStores = getDiskStores();

        //this.procs = getProcessInfo(new Proc());


    }


    /**
     * 字节转换
     *
     * @param size 字节大小
     * @return 转换后值
     */
    public static String convertFileSize(long size) {
        long kb = 1024;
        long mb = kb * 1024;
        long gb = mb * 1024;
        if (size >= gb) {
            return String.format("%.1f GB", (float) size / gb);
        } else if (size >= mb) {
            float f = (float) size / mb;
                return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f);
        } else if (size >= kb) {
            float f = (float) size / kb;
            return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f);
        } else {
            return String.format("%d B", size);
        }
    }


    /**
     * 获取cpu信息
     */
    public static Cpu getCpuInfo() {
        Cpu cpu = new Cpu();
        SystemInfo si = new SystemInfo();
        CentralProcessor processor = si.getHardware().getProcessor();
        // CPU信息
        long[] prevTicks = processor.getSystemCpuLoadTicks();
        Util.sleep(OSHI_WAIT_SECOND);
        long[] ticks = processor.getSystemCpuLoadTicks();
        long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];
        long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];
        long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];
        long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];
        long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];
        long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];
        long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];
        long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];
        long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
        cpu.setCpuNum(processor.getLogicalProcessorCount());
        cpu.setTotal(totalCpu);
        cpu.setSys(cSys);
        cpu.setUsed(user);
        cpu.setWait(iowait);
        cpu.setFree(idle);

        CentralProcessor.ProcessorIdentifier identifier = processor.getProcessorIdentifier();
        cpu.setOsCpuIdentifierName(identifier.getName());
        cpu.setOsLoadAverage(processor.getSystemLoadAverage(3));
        return cpu;
    }


    /**
     * 获取Java虚拟机信息
     *
     * @return
     */
    public static Jvm getJvmInfo() {
        Jvm jvm = new Jvm();
        Properties props = System.getProperties();
        jvm.setTotal(Runtime.getRuntime().totalMemory());
        jvm.setMax(Runtime.getRuntime().maxMemory());
        jvm.setFree(Runtime.getRuntime().freeMemory());
        //jvm.setJavaVersion(props.getProperty("java.version"));
        jvm.setJavaVersion(SystemUtil.getJavaRuntimeInfo().getVersion());
        jvm.setHome(props.getProperty("java.home"));
        return jvm;
    }

    /**
     * 设置内存信息
     */
    public static Mem getMemInfo() {
        Mem mem = new Mem();
        SystemInfo si = new SystemInfo();
        GlobalMemory memory = si.getHardware().getMemory();
        mem.setMemTotal(memory.getTotal());
        mem.setMemUsed(memory.getTotal() - memory.getAvailable());
        mem.setMemFree(memory.getAvailable());
        return mem;
    }

    /**
     * 设置服务器信息
     *
     * @return
     */
    public static OSSys getSysInfo() {
        OSSys OSSys = new OSSys();
        Properties props = System.getProperties();
        HostInfo hostInfo = SystemUtil.getHostInfo();
        String name = hostInfo.getName();
        OSSys.setComputerName(name);
        OSSys.setComputerIp(NetUtil.getLocalhostStr());
        OSSys.setOsName(props.getProperty("os.name"));
        OSSys.setOsArch(props.getProperty("os.arch"));
        OSSys.setUserDir(props.getProperty("user.dir"));

        /**
         * 获取系统其他信息
         */

        OperatingSystem os = OshiUtil.getOs();
        HardwareAbstractionLayer hardware = OshiUtil.getHardware();

        OSSys.setSystemUptime(os.getSystemUptime());
        String manufacturer = os.getManufacturer();
        String family = os.getFamily();
        OperatingSystem.OSVersionInfo versionInfo = os.getVersionInfo();
        String versionStr = versionInfo.toString();
        NetworkParams networkParams = os.getNetworkParams();
        OSSys.setOsVersion(StrUtil.format("{} {} {}", manufacturer, family, versionStr));
        OSSys.setHostName(networkParams.getHostName());
        List<NetworkIF> networks = hardware.getNetworkIFs();

        List<String> collect = networks.stream()
                .flatMap((Function<NetworkIF, Stream<String>>) network -> Arrays.stream(network.getIPv4addr()))
                .collect(Collectors.toList());
        OSSys.setHostIpv4s(collect);
        ComputerSystem computerSystem = hardware.getComputerSystem();
        OSSys.setHardwareVersion(StrUtil.format("{} {}", computerSystem.getManufacturer(), computerSystem.getModel()));


        return OSSys;
    }


    /**
     * 获取进程信息
     *
     * @param proc
     * @return
     */
    public List<Proc> getProcessInfo(Proc proc) {
        //String procPath = System.getenv("PROC_PATH");
        //if (procPath != null) {
        //    // 强制 Oshi 从挂载路径读取/proc信息
        //    System.setProperty("oshi.util.procfs.path", procPath);
        //    // 强制使用 systemd 检测（关键配置！）
        //    System.setProperty("oshi.os.linux.init.system", "systemd");
        //    // 增加调试日志
        //    System.setProperty("oshi.log.level", "DEBUG");
        //}
        //System.out.println("wcb打印2025/6/14 13:14【SystemHardwareInfo.getProcessInfo:218】procPath => " + procPath);

        SystemInfo systemInfo = new SystemInfo();
        OperatingSystem os = systemInfo.getOperatingSystem();
        System.out.println("系统进程信息:");
        System.out.println("当前运行的进程数: " + os.getProcessCount());
        System.out.println("当前运行的线程数: " + os.getThreadCount());


        List<OSProcess> processes = os.getProcesses(
                osProcess -> StringUtils.isBlank(proc.getName()) ? true : StrUtil.equalsIgnoreCase(osProcess.getName(), proc.getName()),
                OperatingSystem.ProcessSorting.CPU_DESC,
                proc.getShowCount() == null ? 20 : Integer.valueOf(proc.getShowCount() + ""));
        // 获取前10个CPU使用率最高的进程
        //List<OSProcess> processes = os.getProcesses(
        //        p -> pro.getName() == null ? true : p.getName().toLowerCase().contains(pro.getName()) || p.getCommandLine().toLowerCase().contains(pro.getName())
        //        ,
        //        //Comparator.comparingLong(OSProcess::getThreadCount).reversed()
        //        Comparator.comparingLong(OSProcess::getUpTime)
        //        , pro.getShowCount() == null ? 20 : Integer.valueOf(pro.getShowCount() + ""));
        List<Proc> collect = processes.stream().map(e -> {
            Proc dto = BeanUtil.copyProperties(e, Proc.class);
            dto.setUpTimeFormat(DateUtil.formatBetween(e.getUpTime()));
            dto.setResidentSetSizeFormat(FormatUtil.formatBytes(e.getResidentSetSize()));
            dto.setVirtualSizeFormat(FormatUtil.formatBytes(e.getVirtualSize()));
            //List<OSThread> threadDetails = e.getThreadDetails();
            //dto.setThreadDetails(threadDetails);
            return dto;
        }).collect(Collectors.toList());
        return collect;
    }

    /**
     * 杀死进程
     *
     * @param pid
     * @return
     */
    public boolean killProcess(int pid) {
        try {
            String osName = System.getProperty("os.name").toLowerCase();
            ProcessBuilder pb;
            if (osName.contains("win")) {
                // Windows强制终止进程
                pb = new ProcessBuilder("taskkill", "/F", "/PID", String.valueOf(pid));
            } else {
                // Linux/macOS强制终止进程
                pb = new ProcessBuilder("kill", "-9", String.valueOf(pid));
            }
            Process process = pb.start();
            int exitCode = process.waitFor();
            return exitCode == 0;
        } catch (Exception e) {
            System.err.println("强制终止进程失败: " + e.getMessage());
            return false;
        }
    }

    /**
     * 获取文件系统信息 设置磁盘信息
     *
     * @return {
     * "uuid": "89b5b98b-7070-4890-b8ea-c980fe0daf99",
     * "name": "本地固定磁盘 (C:)",
     * "mount": "C:\\",
     * "fileSysType": "NTFS",
     * "desc": "Fixed drive",
     * "free": "3.6 GB",
     * "total": "100.0 GB",
     * "used": "96.4 GB",
     * "usage": "96.38%",
     * "option": "rw,reparse,sparse,trans,journaled,quota,casess,oids,casepn,efs,streams,unicode,acls,fcomp",
     * "freeInodes": 0,
     * "totalInodes": 0
     * },
     */
    public static ArrayList<FileSys> getOsDiskFile() {
        SystemInfo si = new SystemInfo();
        OperatingSystem os = si.getOperatingSystem();
        FileSystem fileSystem = os.getFileSystem();
        ArrayList<FileSys> OSFileSIES = new ArrayList<>();
        for (OSFileStore fs : fileSystem.getFileStores()) {
            long free = fs.getUsableSpace();
            long total = fs.getTotalSpace();
            long used = total - free;
            FileSys df = new FileSys();
            df.setUuid(fs.getUUID());
            df.setName(fs.getName());
            df.setMount(fs.getMount());
            df.setFileSysType(fs.getType());
            df.setDesc(fs.getDescription());
            df.setFree(convertFileSize(free));
            df.setTotal(convertFileSize(total));
            df.setUsed(convertFileSize(used));
            df.setUsage(NumberUtil.formatPercent((float) used / total, 2));
            df.setOption(fs.getOptions());
            df.setFreeInodes(fs.getFreeInodes());
            df.setTotalInodes(fs.getTotalInodes());
            OSFileSIES.add(df);
        }
        return OSFileSIES;
    }

    public static List<DiskStores> getDiskStores() {
        HardwareAbstractionLayer hardware = OshiUtil.getHardware();
        List<HWDiskStore> diskStores = hardware.getDiskStores();

        return diskStores.stream().map(disk -> {
            DiskStores ods = new DiskStores();
            ods.setTimeStamp(disk.getTimeStamp());
            ods.setName(disk.getName());
            ods.setModel(disk.getModel());
            ods.setSerial(disk.getSerial());
            ods.setSize(disk.getSize());
            ods.setReadBytes(disk.getReadBytes());
            ods.setReads(disk.getReads());
            ods.setWriteBytes(disk.getWriteBytes());
            ods.setWrites(disk.getWrites());
            ods.setCurrentQueueLength(disk.getCurrentQueueLength());
            ods.setTransferTime(disk.getTransferTime());
            ArrayList<DiskStores.PartitionDTO> list = new ArrayList<>();
            List<HWPartition> partitions = disk.getPartitions();
            for (HWPartition hwPartition : partitions) {
                DiskStores.PartitionDTO partitionDTO = new DiskStores.PartitionDTO();
                partitionDTO.setIdentification(hwPartition.getIdentification());
                partitionDTO.setName(hwPartition.getName());
                partitionDTO.setType(hwPartition.getType());
                partitionDTO.setMajor(hwPartition.getMajor());
                partitionDTO.setMinor(hwPartition.getMinor());
                partitionDTO.setSize(hwPartition.getSize());
                partitionDTO.setMountPoint(hwPartition.getMountPoint());
                partitionDTO.setUuid(hwPartition.getUuid());
                list.add(partitionDTO);
            }
            ods.setPartition(list);
            return ods;
        }).collect(Collectors.toList());
    }
}